package org.iabako.client.navigation;

import com.google.gwt.event.shared.UmbrellaException;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException;
import com.google.gwt.user.client.rpc.InvocationException;
import com.google.gwt.user.client.rpc.StatusCodeException;
import org.iabako.client.ui.layout.widget.dialogbox.IabakoDialogBox;
import org.iabako.client.ui.layout.widget.validation.ValidationMessage;
import org.iabako.shared.iservice.support.SupportActionServiceAsync;

import java.util.logging.Logger;

/**
 * Created by jose on 15/10/14.
 */
public class FailureController {

    static Logger log = Logger.getLogger(FailureController.class.getName());

    protected final SupportActionServiceAsync supportActionServiceAsync = SupportActionServiceAsync.Util.getInstance();

    public static void handleFailure(Throwable caught) {
        try {
            new FailureController().handleFailure(caught, false, true);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

    public void handleFailure(Throwable caught, boolean gwtHandleException, boolean logException) {

        if (gwtHandleException) {
            log.severe(handleLogException(logException, unwrap(caught)));
            return;
        }

        // 1. Check no session error
        if (isSessionExpiredError(caught)) {
            return;
        }

        // 2. Check other errors
        if (caught instanceof IncompatibleRemoteServiceException) {
            //This client is not compatible with the server; Refresh the browser
            showTechnicalErrorDialogBox();

        } else if (caught instanceof StatusCodeException
                && ((StatusCodeException) caught).getStatusCode() >= 500
                && ((StatusCodeException) caught).getStatusCode() < 600) {
            // 5xx Server error
            showTechnicalErrorDialogBox();
            handleLogException(logException, caught);

        } else if (caught instanceof InvocationException) {
            // the call didn't complete cleanly (ex. not Internet connection)
            showNoInternetDialogBox();
        } else {
            //Something unexpected...
            showTechnicalErrorDialogBox();
            handleLogException(logException, caught);
        }
    }

    private Throwable unwrap(Throwable e) {
        if (e instanceof UmbrellaException) {
            UmbrellaException ue = (UmbrellaException) e;
            if (ue.getCauses().size() == 1) {
                return unwrap(ue.getCauses().iterator().next());
            }
        }
        return e;
    }

    private String handleLogException(boolean logException, Throwable caught) {
        if (!logException) {
            return null;
        }
        String exceptions = "";
        if (caught != null) {
            exceptions += caught.toString() + "\n";
            while (caught != null) {
                for (StackTraceElement element : caught.getStackTrace()) {
                    if (element.toString().contains("iabako")) {
                        exceptions += element.toString() + "\n";
                    }
                }
                caught = caught.getCause();
            }
        }
        exceptions += "Last visited pages : " + PageInstanceGetter.getLastVisitedPages();

        supportActionServiceAsync.logException(exceptions, new AsyncCallback<Void>() {
            public void onFailure(Throwable throwable) {
                //Do nothing
            }

            public void onSuccess(Void aVoid) {
                //Do nothing
            }
        });
        return exceptions;
    }

    private static void showTechnicalErrorDialogBox() {
        clearMessagesAndPopups();

        IabakoDialogBox iabakoDialogBox = new IabakoDialogBox("technical_error_title", "technical_error_message", "technicalerroricon") {
            @Override
            protected void customCloseButtonHandler() {
                Window.Location.reload();
            }
        };
        NavigationController.getInstance().show(iabakoDialogBox);
    }

    private static void showNoInternetDialogBox() {
        clearMessagesAndPopups();
        NavigationController.getInstance().show(new IabakoDialogBox("ping_error_title", "ping_error_message", "nointerneterroricon"));
    }

    private static void clearMessagesAndPopups() {
        if (ValidationMessage.getFirstFromDOM() != null) {
            ValidationMessage.getFirstFromDOM().clear();
        }
        NavigationController.getInstance().closePopups();
    }

    private static boolean isSessionExpiredError(Throwable caught) {
        // Session expired verification
        if (caught.getMessage().contains("_authentication_error_")) {
            String host = Window.Location.getHost();
            String url = Window.Location.getHref();
            Window.Location.replace(url.substring(0, url.indexOf(host) + host.length()) + "/");
            return true;
        }
        return false;
    }
}
